package co.baiku.boot.request;

import co.baiku.boot.common.tools.StringTools;
import co.baiku.boot.common.validate.Validation;
import co.baiku.boot.type.WeixinPayTradeType;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

/**
 * 提交付款码支付
 */
public class WeixinMicropayRequest implements WeixinPayRequest {
    /**
     * 扫码支付授权码(必填)
     * <p>
     * 设备读取用户微信中的条码或者二维码信息
     * （注：用户付款码条形码规则：18位纯数字，以10、11、12、13、14、15开头）
     * </p>
     */
    private String auth_code;
    /**
     * 子商户公众账号ID(选填)
     * <p>
     * 微信分配的子商户公众账号ID，如需在支付完成后获取sub_openid则此参数必传。
     * </p>
     */
    private String sub_appid;
    /**
     * 子商户号(支付服务商时必填)
     * <p>
     * 微信支付分配的子商户号
     * </p>
     */
    private String sub_mch_id;

    /**
     * 商品描述(必填)
     * <p>
     * 商品简单描述，该字段须严格按照规范传递，<a href='https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_sl_api.php?chapter=4_2'>具体请见参数规定</a>
     * </p>
     */
    private String body;
    /**
     * 商品详情(选填)
     * <p>
     * 商品详细描述，对于使用单品优惠的商户，改字段必须按照规范上传，详见“<a href='https://pay.weixin.qq.com/wiki/doc/api/wxa/danpin.php?chapter=9_102&index=2'>单品优惠参数说明</a>”
     * </p>
     */
    private String detail;

    /**
     * 设备号(选填)
     * <p>
     * 终端设备号(门店号或收银设备ID)，注意：PC网页或公众号内支付请传"WEB"
     * </p>
     */
    private String device_info;

    /**
     * 附加数据(选填)
     * <p>附加数据，在查询API和支付通知中原样返回，该字段主要用于商户携带订单的自定义数据</p>
     */
    private String attach;

    /**
     * 商户订单号(必填)
     * <p>商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|*且在同一个商户号下唯一。<a href='https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_sl_api.php?chapter=4_2'>详见商户订单号</a></p>
     */
    private String out_trade_no;

    /**
     * 货币类型(选填)
     * <p>符合ISO 4217标准的三位字母代码，默认人民币：CNY，其他值列表详见<a href='https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_sl_api.php?chapter=4_2'>货币类型</a></p>
     */
    private String fee_type = "CNY";

    /**
     * 总金额(必填)
     * <p>订单总金额，只能为整数，详见<a href='https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_sl_api.php?chapter=4_2'>支付金额</a></p>
     */
    private Integer total_fee;

    /**
     * 终端IP(必填)
     * <p>APP和H5支付提交用户端ip，Native支付填调用微信支付API的机器IP</p>
     */
    private String spbill_create_ip;

    /**
     * 交易起始时间(选填)
     * <p>订单生成时间，格式为yyyyMMddHHmmss，如2009年12月25日9点10分10秒表示为20091225091010。其他详见<a href='https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_sl_api.php?chapter=4_2'>时间规则</a></p>
     */
    private String time_start;

    /**
     * 交易结束时间(选填)
     * <p>订单失效时间，格式为yyyyMMddHHmmss，如2009年12月27日9点10分10秒表示为20091227091010。订单失效时间是针对订单号而言的，由于在请求支付的时候有一个必传参数prepay_id只有两小时的有效期，所以在重入时间超过2小时的时候需要重新请求下单接口获取新的prepay_id。其他详见<a href='https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_sl_api.php?chapter=4_2'>时间规则</a>
     * <br/>
     * <span style='color:red'>建议：最短失效时间间隔大于1分钟</span></p>
     */
    private String time_expire;

    /**
     * 订单优惠标记(选填)
     * <p>订单优惠标记，代金券或立减优惠功能的参数，说明详见<a href='https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_1'>代金券或立减优惠</a></p>
     */
    private String goods_tag;


    /**
     * 交易类型(必填)
     */
    private WeixinPayTradeType trade_type;

    /**
     * 指定支付方式(选填)
     * <p>no_credit--指定不能使用信用卡支付</p>
     */
    private String limit_pay;

    /**
     * 用户子标识(选填)
     * <p>
     * trade_type=JSAPI，此参数必传，用户在子商户appid下的唯一标识。openid和sub_openid可以选传其中之一，如果选择传sub_openid,则必须传sub_appid。下单前需要调用【<a href='https://developers.weixin.qq.com/miniprogram/dev/api/wx.login.html'>网页授权获取用户信息</a>】接口获取到用户的Openid。
     * </p>
     */
    private String sub_openid;

    /**
     * 电子发票入口开放标识
     * <p>Y，传入Y时，支付成功消息和支付详情页将出现开票入口。需要在微信支付商户平台或微信公众平台开通电子发票功能，传此字段才可生效</p>
     */
    private String receipt;

    /**
     * 场景信息
     * <p>
     * 该字段用于上报场景信息，目前支持上报实际门店信息。该字段为JSON对象数据，对象格式为{"store_info":{"id": "门店ID","name": "名称","area_code": "编码","address": "地址" }} <br />
     * eg:
     * <pre>
     * {
     *   "store_info": {
     *       "id": "SZTX001",
     *       "name": "腾大餐厅",
     *       "area_code": "440305",
     *       "address": "科技园中一路腾讯大厦"
     *    }
     * }
     *     </pre>
     * </p>
     */
    private String scene_info;

    @Override
    public Map<String, String> toMap() {
        //18位纯数字，以10、11、12、13、14、15开头
        if (StringTools.isBlank(this.auth_code)) {
            throw Validation.error("授权码不能为空");
        }
        boolean match = StringTools.regexMatch(this.auth_code, "1([0-5]{1})[0-9]{16}");
        if (!match) {
            throw Validation.error("授权码无效");
        }
        Map<String, String> data = new HashMap<>();
        data.put("auth_code", auth_code);
        data.put("body", body);
        data.put("detail", detail);
        data.put("attach", attach);
        data.put("fee_type", fee_type);
        data.put("out_trade_no", out_trade_no);
        data.put("total_fee", String.valueOf(total_fee));
        data.put("spbill_create_ip", spbill_create_ip);
        data.put("time_start", time_start);
        data.put("goods_tag", goods_tag);
        data.put("time_expire", time_expire);
        data.put("device_info", device_info);
        data.put("sub_openid", sub_openid);
        data.put("limit_pay", limit_pay);
        data.put("sub_mch_id", sub_mch_id);
        data.put("sub_appid", sub_appid);
        data.put("receipt", receipt);
        HashSet<String> toRm = new HashSet();
        data.forEach((k, v) -> {
            if (v == null) {
                toRm.add(k);
            }
        });
        for (String o : toRm) {
            data.remove(o);
        }
        return data;
    }

    public String getScene_info() {
        return scene_info;
    }

    public void setScene_info(String scene_info) {
        this.scene_info = scene_info;
    }

    public String getAuth_code() {
        return auth_code;
    }

    public void setAuth_code(String auth_code) {
        this.auth_code = auth_code;
    }

    public String getSub_appid() {
        return sub_appid;
    }

    public void setSub_appid(String sub_appid) {
        this.sub_appid = sub_appid;
    }

    public String getSub_mch_id() {
        return sub_mch_id;
    }

    public void setSub_mch_id(String sub_mch_id) {
        this.sub_mch_id = sub_mch_id;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    public String getDevice_info() {
        return device_info;
    }

    public void setDevice_info(String device_info) {
        this.device_info = device_info;
    }

    public String getAttach() {
        return attach;
    }

    public void setAttach(String attach) {
        this.attach = attach;
    }

    public String getOut_trade_no() {
        return out_trade_no;
    }

    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }

    public String getFee_type() {
        return fee_type;
    }

    public void setFee_type(String fee_type) {
        this.fee_type = fee_type;
    }

    public Integer getTotal_fee() {
        return total_fee;
    }

    public void setTotal_fee(Integer total_fee) {
        this.total_fee = total_fee;
    }

    public String getSpbill_create_ip() {
        return spbill_create_ip;
    }

    public void setSpbill_create_ip(String spbill_create_ip) {
        this.spbill_create_ip = spbill_create_ip;
    }

    public String getTime_start() {
        return time_start;
    }

    public void setTime_start(String time_start) {
        this.time_start = time_start;
    }

    public String getTime_expire() {
        return time_expire;
    }

    public void setTime_expire(String time_expire) {
        this.time_expire = time_expire;
    }

    public String getGoods_tag() {
        return goods_tag;
    }

    public void setGoods_tag(String goods_tag) {
        this.goods_tag = goods_tag;
    }

    public WeixinPayTradeType getTrade_type() {
        return trade_type;
    }

    public void setTrade_type(WeixinPayTradeType trade_type) {
        this.trade_type = trade_type;
    }

    public String getLimit_pay() {
        return limit_pay;
    }

    public void setLimit_pay(String limit_pay) {
        this.limit_pay = limit_pay;
    }

    public String getSub_openid() {
        return sub_openid;
    }

    public void setSub_openid(String sub_openid) {
        this.sub_openid = sub_openid;
    }

    public String getReceipt() {
        return receipt;
    }

    public void setReceipt(String receipt) {
        this.receipt = receipt;
    }

}
